package org.springframework.boot.netty.argumentResolver;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import io.netty.handler.codec.http.FullHttpRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.netty.annotation.RequestEntity;
import org.springframework.boot.netty.exception.ConvertException;
import org.springframework.boot.netty.listener.Message;
import org.springframework.boot.netty.support.HttpParamParser;
import org.springframework.boot.netty.support.JsonUtil;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Author: huoxingzhi
 * Date: 2020/12/16
 * Email: hxz_798561819@163.com
 */
public class RequestEntityMethodArgumentResolver extends HandlerMethodArgumentResolverAdapter {

    @Override
    public boolean supportsParameter(Class<?> receiveClass,MethodParameter methodParameter) {
        RequestEntity requestEntity = methodParameter.getParameter().getAnnotation(RequestEntity.class);
        return !ObjectUtils.isEmpty(requestEntity);
    }

    @Override
    public Object resolveArgument(Message message, MethodParameter methodParameter) throws ConvertException {

        try {
            Class<?> paramType = methodParameter.getParameter().getType();
            Object object = paramType.newInstance();
            Map<String, Field> fieldMap = new HashMap<>(32);
            ReflectionUtils.doWithFields(object.getClass(), field -> {
                fieldMap.put(field.getName(),field);
            });
            FullHttpRequest httpRequest = (FullHttpRequest)message.getContent();
            Map<String, Object> parseParams = HttpParamParser.parseParams(httpRequest);
            Map<String,JSONArray> jsonObjects = new HashMap<>();

            for (String paramKey : parseParams.keySet()) {

                if(paramKey.contains("[") ){
                    String paramKeyToUse = StringUtils.substringBefore(paramKey,"[");
                    JSONArray jsonArray = null;
                    if(jsonObjects.containsKey(paramKeyToUse)){
                        jsonArray = jsonObjects.get(paramKeyToUse);
                    }else {
                        jsonArray = new JSONArray();
                        jsonObjects.put(paramKeyToUse,jsonArray);
                    }

                    //获取索引值
                    int index = Integer.valueOf(StringUtils.substringBetween(paramKey, "[", "]"));
                    if(null==jsonArray.get(index)){
                        jsonArray.add(index,new JSONObject());
                    }

                    JsonObject nestedJsonObject = (JsonObject) jsonArray.get(index);
                    String innerObjectParam = StringUtils.substringAfter(paramKey,".");
                    Object innerObjectValue = parseParams.get(paramKey);
                    nestedJsonObject.addProperty(innerObjectParam,(String)innerObjectValue);


                    // 补充缺少的对象 版本迭代替换为了构造jsonObject
                    // list属性
                    // 1. 初始化list属性
                /*    List fieldInstance = (List) field.get(paramValueToUse);
                    if(fieldInstance.size() <= index) {
                        int missingValue = index - fieldInstance.size() + 1;
                        Type t = field.getGenericType();
                        if (t instanceof ParameterizedType) {
                            ParameterizedType pt = (ParameterizedType) t;
                            Class clz = (Class) pt.getActualTypeArguments()[0];//得到对象list中实例的类型
                            for(int i = 0; i < missingValue; i++){
                                fieldInstance.add(clz.newInstance());
                            }
                        }
                    }

                    String innerObjectParam = StringUtils.substringBetween(paramKey,".","=");
                    String innerObjectValue = StringUtils.substringAfter(paramKey,"=");
                    Field innerField = fieldInstance.get(index).getClass().getDeclaredField(innerObjectParam);
                    ReflectionUtils.makeAccessible(innerField);
                    innerField.set(fieldInstance.get(index), innerObjectValue);
                    */

                }else if(paramKey.contains(".")) {
                    String paramValueToUse = StringUtils.substringBefore(paramKey,".");
                    Field field = fieldMap.get(paramValueToUse);
                    ReflectionUtils.makeAccessible(field);
                    Object value = field.get(object);
                    if(null == value){
                        field.set(object,field.getType().newInstance());
                    }
                    Object fieldInstance = field.get(object);

                    //级联属性
                    String innerObjectParam = StringUtils.substringAfter(paramKey,".");
                    Object innerObjectValue = parseParams.get(paramKey);
                    Field innerField = fieldInstance.getClass().getDeclaredField(innerObjectParam);
                    ReflectionUtils.makeAccessible(innerField);

                    if(this.conversionService.canConvert(String.class,innerField.getType())){
                       Object convertdInnerObjectValue
                               = this.conversionService
                               .convert(innerObjectValue,innerField.getType());
                        innerField.set(fieldInstance,convertdInnerObjectValue);
                    }


                }else{
                    // 普通属性
                   Object paramValue = parseParams.get(paramKey);
                    Field field = fieldMap.get(paramKey);
                    ReflectionUtils.makeAccessible(field);
                    if(this.conversionService.canConvert(paramValue.getClass(),field.getType())){
                        Object convertdObjectValue = this.conversionService.convert(paramValue,field.getType());
                        field.set(object,convertdObjectValue);
                    }
                }
            }


            // process jsonObject
            jsonObjects.entrySet().stream().forEach(jsonArrayEntry -> {

                String fieldName = jsonArrayEntry.getKey();
                String jsonFieldValue = jsonArrayEntry.getValue().toJSONString();
                Field field = fieldMap.get(fieldName);

                Type t = field.getGenericType();
                ParameterizedType pt = (ParameterizedType) t;
                Class clz = (Class) pt.getActualTypeArguments()[0];//得到对象list中实例的类型
                Object o = JsonUtil.string2Obj(jsonFieldValue, List.class, clz);
                ReflectionUtils.makeAccessible(field);
                try {
                    field.set(object, o);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });

            return object;

        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }


    @Override
    public Object resolveAndConvertArgument(Message message, MethodParameter methodParameter) {

        return resolveArgument(message, methodParameter);

    }
}
